package top.jfunc.common.compress;

import top.jfunc.common.utils.ArrayUtil;
import top.jfunc.common.utils.IoUtil;

import java.io.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * gzip压缩算法实现压缩解压
 * @author xiongshiyan at 2022/5/26 , contact me with email yanshixiong@126.com or phone 15208384257
 */
public class GzipCompressor implements Compressor{
    private int bufferSize = IoUtil.DEFAULT_BUFFER_SIZE;
    public GzipCompressor(){
    }
    public GzipCompressor(int bufferSize){
        this.bufferSize = bufferSize;
    }


    @Override
    public byte[] compress(byte[] src, int offset, int length) throws CompressException {
        //字节数组输出流，在内存中创建一个字节数组缓冲区，所有发送到输出流的数据保存在该字节数组 缓冲区中。解压缩通常用于此流
        //gzip的输出流（压缩）
        try (ByteArrayOutputStream out = new ByteArrayOutputStream();
             GZIPOutputStream gzip = new GZIPOutputStream(out)){

            //将数据转换为字符放进流里进行压缩
            gzip.write(src, offset, length);
            gzip.finish();

            return out.toByteArray();

        } catch (Exception e) {
            throw new CompressException(e);
        }
    }
    @Override
    public byte[] compress(byte[] src, byte[]...more) throws CompressException {
        //字节数组输出流，在内存中创建一个字节数组缓冲区，所有发送到输出流的数据保存在该字节数组 缓冲区中。解压缩通常用于此流
        //gzip的输出流（压缩）
        try (ByteArrayOutputStream out = new ByteArrayOutputStream();
             GZIPOutputStream gzip = new GZIPOutputStream(out)){

            //将数据转换为字符放进流里进行压缩
            gzip.write(src);
            if(ArrayUtil.isNotEmpty(more)){
                for (byte[] bytes : more) {
                    gzip.write(bytes);
                }
            }
            gzip.finish();

            return out.toByteArray();

        } catch (Exception e) {
            throw new CompressException(e);
        }
    }
    @Override
    public byte[] compress(InputStream src) throws CompressException {
        //字节数组输出流，在内存中创建一个字节数组缓冲区，所有发送到输出流的数据保存在该字节数组 缓冲区中。解压缩通常用于此流
        //gzip的输出流（压缩）
        try (ByteArrayOutputStream out = new ByteArrayOutputStream();
             GZIPOutputStream gzip = new GZIPOutputStream(out)){

            //将数据转换为字符放进流里进行压缩
            IoUtil.copy(src,gzip,bufferSize);
            gzip.finish();

            return out.toByteArray();

        } catch (Exception e) {
            throw new CompressException(e);
        }
    }

    @Override
    public byte[] unCompress(byte[] src, int offset, int length) throws CompressException {
        try (GZIPInputStream ginzip = new GZIPInputStream(new ByteArrayInputStream(src, offset, length));
             ByteArrayOutputStream out = new ByteArrayOutputStream()){

            //代表将按照字节数组输入的方式进行解压
            IoUtil.copy(ginzip,out,bufferSize);

            return out.toByteArray();

        } catch (Exception e) {
                 e.printStackTrace();
            throw new CompressException(e);
        }
    }


    @Override
    public byte[] unCompress(InputStream src) throws CompressException {
        //声明一个字符数组输出流，用于写入
        try (GZIPInputStream ginzip = new GZIPInputStream(src);
             ByteArrayOutputStream out = new ByteArrayOutputStream()){

            //声明每次读取和写入的大小，通常为1024
            IoUtil.copy(ginzip,out,bufferSize);

            return out.toByteArray();

        } catch (Exception e) {
            throw new CompressException(e);
        }
    }

    @Override
    public String toString(){
        return getClass().getName();
    }
}
